﻿<html>
<head>
<link rel="stylesheet" type="text/css" href="HuskyMessageMap.css">
</head>
<body>
<div id="file_list_div">
	<table border="1" class="pretty_tbl" style="width:500px"><tr><th style="width:100%">Message Map Creator</th><th style="text-align:right"><button style="align:right;width:180px" onclick="displayHuskyManual();">Create Message List</button></th></tr>
	<tr><td colspan="2">
	<textarea id="file_list" rows="40" style="width: 100%">js_src/hp_ActiveLayerManager.js
js_src/hp_CorePlugin.js
js_src/hp_DialogLayerManager.js
js_src/hp_Hotkey.js
js_src/hp_HuskyRangeManager.js
js_src/hp_MessageManager.js
js_src/hp_SE_BGColor.js
js_src/hp_SE_ColorPalette.js
js_src/hp_SE_EditingAreaManager.js
js_src/hp_SE_EditingAreaVerticalResizer.js
js_src/hp_SE_EditingArea_HTMLSrc.js
js_src/hp_SE_EditingArea_WYSIWYG.js
js_src/hp_SE_EditingModeToggler.js
js_src/hp_SE_ExecCommand.js
js_src/hp_SE_FindReplacePlugin.js
js_src/hp_SE_FontColor.js
js_src/hp_SE_FontNameWithSelectUI.js
js_src/hp_SE_FontSizeWithSelectUI.js
js_src/hp_SE_Hyperlink.js
js_src/hp_SE_LineHeight.js
js_src/hp_SE_LineHeightWithSelectUI.js
js_src/hp_SE_OuterIFrameControl.js
js_src/hp_SE_Quote.js
js_src/hp_SE_SCharacter.js
js_src/hp_SE_Table.js
js_src/hp_SE_Toolbar.js
js_src/hp_SE_UndoRedo.js
js_src/hp_SE_WYSIWYGEnterKey.js
js_src/hp_SE_WYSIWYGStyleGetter.js
js_src/hp_SE_WYSIWYGStyler.js
js_src/hp_StringConverterManager.js
js_src/hp_Utils.js</textarea>
	</td></tr>
	</table>
</div>
<div id="doc_table_div" style="display:none">
	<div class="view_mode_div">
	<span id="idMsgSpan">메시지</span>
	<span id="idPluginSpan">플러그인</span>
	</div>
	<table id="idMsgTbl" border="1" class="pretty_tbl"><tr><th>메시지</th><th>파라미터</th><th>메시지 설명</th><th>발생 플러그인</th><th>ON 핸들러</th><th>BEFORE 핸들러</th><th>AFTER 핸들러</th></tr></table>

	<table id="idPluginTbl" border="1" class="pretty_tbl"><tr><th>플러그인</th><th>플러그인 설명</th><th>발생 메시지</th><th>ON 핸들러</th><th>BEFORE 핸들러</th><th>AFTER 핸들러</th></tr></table>
</div>

</body>
<script>
var HTMLElmWrapper = {};

HTMLElmWrapper.removeAllChildren = function(nodeWithChildren){
	while (nodeWithChildren.childNodes.length >= 1) {
		nodeWithChildren.removeChild(nodeWithChildren.firstChild);
	}
}

HTMLElmWrapper.getType = function(v){
	var result = typeof(v);
	if (result == "object"){
		result = "@anonymous";

		if(v.constructor){
			var sConstructor = v.constructor.toString();
			var iStartIdx = sConstructor.indexOf(' ') + 1;
			var iEndIdx = sConstructor.indexOf('(') - iStartIdx;
	
			result = sConstructor.substr(iStartIdx, iEndIdx);
			if (iStartIdx == 0 || result == "") result = "@anonymous";
		}
	}
	return result;
}

/**
 * Returns an element that should be "wrapped" by the wrapping function based on a given element which basically tells where the wrapee should be placed. 
 * This function is used mainly because of the following 3 distinctive cases.   
 * <ul>
 * <li>1) "obj" is what needs to be wrapped
 * <li>2) "obj" is a DIV and the wrapee should be placed inside the DIV
 * <li>3) "obj" is neither of the above two and should be replaced by the wrapee
 * </ul>
 * @param {object} obj tells where the wrapee should be placed
 * @param {string} tagName tells what should be placed
 * @return {object} wrapee
 */
HTMLElmWrapper.placeWrapper = function(obj, tagName){
	var oWrapee;
	
	// the 1st case, return the obj
	if(obj.tagName == tagName){
		oWrapee = obj;
	}else{
		oWrapee = document.createElement(tagName);
		
		// the 2nd case, insert the wrapee inside the DIV
		if(obj.tagName == "DIV"){
			obj.appendChild(oWrapee);
		}else{
			// the 3rd case, insert the wrapee before the obj and then hide the obj 
			obj.parentNode.insertBefore(oWrapee, obj);
			obj.style.display = "none";					
		}
	}
	return oWrapee;
} 

HTMLElmWrapper.wrapperTable = function(id){
	var obj = document.getElementById(id);
	var oTable;
	var oTBody;
	var numColumns = 1;
	var numRows = 1;

	oTable = HTMLElmWrapper.placeWrapper(obj, "TABLE");
	
	obj = obj.getElementsByTagName("TBODY");
	if(!obj || !obj[0]){
		oTBody = document.createElement("TBODY");
		oTable.appendChild(oTBody);
	}else{
		oTBody = obj[0];
	}

	this.getCells = function(){	
		return oTable.getElementsByTagName('td');
	}
				
	this.removeCells = function(){
		if(oTable.hasChildNodes()){
			var count = oTable.childNodes.length;

			for(i = count-1; i > -1; i--){
				var oChild = oTable.childNodes[i];
				oTable.removeChild(oChild);
			}
		}
	}
	this.createCells = function(nPColumns, nPRows){
		if(nPColumns) numColumns = nPColumns;
		if(nPRows) numRows = nPRows;

		var oRow;
		var oCell;
		for(var i=0; i<numRows; i++){
			oRow = document.createElement("TR");
			for(var ii=0; ii<numColumns; ii++){
				oCell = document.createElement("TD");
				oCell.innerHTML = "&nbsp";
				oRow.appendChild(oCell);
			}
			oTBody.appendChild(oRow);
		}
	}
	this.createCellsWithColumnFilling = function(filling){
		if(!filling || HTMLElmWrapper.getType(filling) != "Array") return false;
		
		this.setNumColumns(filling.length);
		this.setNumRows(1);
		
		this.createCells();
		
		this.fill(filling);
	}
	this.createCellsWithRowFilling = function(filling){
		if(!filling || HTMLElmWrapper.getType(filling) != "Array") return false;
		
		this.setNumColumns(1);
		this.setNumRows(filling.length);

		this.createCells();

		this.fill(filling);
	}
	
	this.fillIn = function(cell, filling){
		if(HTMLElmWrapper.getType(filling) == "string"){
			cell.innerHTML = filling;
		}else{
			cell.innerHTML = "";
			cell.appendChild(filling);
		}
	}
	
	this.fillArray = function(filling){
		var cells = this.getCells();
		var loopExit = Math.min(cells.length, filling.length);

		for(var i=0; i<loopExit; i++){
			this.fillIn(cells[i], filling[i]);
		}
	}
	
	this.fillNonArray = function(filling){
		var cells = this.getCells();
		var loopExit = cells.length;
			
		for(var i=0; i<loopExit; i++){
			this.fillIn(cells[i], filling);
		}
	}
	
	this.fill = function(filling){
		if(HTMLElmWrapper.getType(filling) == "Array"){
			this.fillArray(filling);
		}else{
			this.fillNonArray(filling);
		}
	}
	
	this.setNumColumns = function(n){numColumns=n;}
	this.setNumRows = function(n){numRows=n;}
	
	this._o = oTable;
}

HTMLElmWrapper.wrapperUL = function(id){
	var obj = document.getElementById(id);
	var oUL;

	oUL = HTMLElmWrapper.placeWrapper(obj, "UL");

	this.setLi = function(pmLi, pmItem){
		if(pmItem.tagName && pmItem.tagName == "LI") return pmItem;

		if(HTMLElmWrapper.getType(pmItem) == "string"){
			pmLi.innerHTML = pmItem;
		}else{
			HTMLElmWrapper.removeAllChildren(pmLi);
			
			pmLi.appendChild(pmItem);
		}
		
		return pmLi; 
	}

	this.addItemNonArray = function(pmItem){
		var oItem;
		oItem = document.createElement("LI");

		oItem = this.setLi(oItem, pmItem);		
		
		oUL.appendChild(oItem);
		
		return oItem;
	}

	this.addItemArray = function(pmItem){
		var loopExit = pmItem.length;

		for(var i=0; i<loopExit; i++){
			this.addItemNonArray(pmItem[i]);
		}
		
		return pmItem[pmItem.length-1];
	}
	
	this.setItemAt = function(iAt, pmItem){
		var oLi = oUL.childNodes.item(iAt);
		this.setLi(oLi, pmItem);
	}
	
	this.addItem = function(pmItem){
		var justAdded;
		
		if(HTMLElmWrapper.getType(pmItem) == "Array"){
			justAdded = this.addItemArray(pmItem);
		}else{
			justAdded = this.addItemNonArray(pmItem);
		}

		return justAdded;
	}
	
	// what : zero indexed index number or an LI object
	this.removeItem = function(what){
		if(!what) return;
		if(what.tagName && what.tagName == "LI"){
			oUL.removeChild(what)
		}else{
			oUL.removeChild(oUL.childNodes.item(what));
		}
	}
	this._o = oUL;
}

// Provide the XMLHttpRequest class for IE 5.x-6.x:
// Other browsers (including IE 7.x-8.x) ignore this
//   when XMLHttpRequest is predefined
if (typeof XMLHttpRequest  === "undefined") {
  XMLHttpRequest = function() {
    try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
      catch(e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
      catch(e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP"); }
      catch(e) {}
    try { return new ActiveXObject("Microsoft.XMLHTTP"); }
      catch(e) {}
    throw new Error("This browser does not support XMLHttpRequest.");
  };
}

function chomp(str){
	if(!str) return str;
	return str.replace(/(\n|\r|\s)*$/, "");
}

function setMsg(sMsgName, sMessage_DESC, oMessage_PARAMS){
	for(var i=0; i<aMessage.length; i++){
		if(aMessage[i]["Message_NAME"] == sMsgName){
			if(sMessage_DESC == ""){
				return;
			}else{
				break;
			}
		}
	}
	aMessage[i] = {"Message_NAME": sMsgName, "Message_DESC": sMessage_DESC, "Message_PARAMS": oMessage_PARAMS};
}

function funcParseOneMsgCmt(){
	var sOrigStr = arguments[0];
	var sAllMsgDesc = arguments[1];

	var sMsgName, sMsgDesc, sMsgParams;

	// From a comment block looks like,
	//
	// * First block line 1
	// * First block line 2
	// *
	// * 2nd block
	// *
	// * 3rd block
	//
	// returns (leading * marks removed)
	//
	// First block line 1
	// First block line 2
	//
	function getFirstBlock(){
		// take string until an empty line(with a *) is found
		sAllMsgDesc = sAllMsgDesc.replace(/^(?:\r|\n)*(((?!\s*\*\s*$)(\r|\n|.))*)/m, "");
		// chomp and remove the leading *'s without removing the line breaker
		var sFirstBlock = chomp(RegExp.$1).replace(/^(([\r\n]*)\s*\*\s*)/gm,"$2");

		// remove the empty line, which is used to be below the first block
		sAllMsgDesc = sAllMsgDesc.replace(/^\s*\*?\s*/, "");

		return sFirstBlock;
	}


	sMsgName = getFirstBlock();
	sMsgDesc = getFirstBlock();
	sMsgParam = getFirstBlock();

	var aParams = [];

	function funcParseEachParam(){
		var sParamName = arguments[1];
		var sParamType = arguments[2];
		var sParamDesc = arguments[3];

		var oOneParam = {};
		oOneParam["PARAM_NAME"] = sParamName;
		oOneParam["PARAM_TYPE"] = sParamType;
		oOneParam["PARAM_DESC"] = sParamDesc;

		aParams[aParams.length] = oOneParam;

		return "";
	}

	sMsgParam.replace(/^\s*(^\S+)(?:\s+)?(\S+)?(?:\s+)?(.+)?/gm, funcParseEachParam);

	setMsg(sMsgName, sMsgDesc, aParams);

	return "";
}

function funcParseOnePluginSrc(sPluginSrc){
	var sPluginDesc = "";
	var sPluginName = "";

	var sHandlerDesc = "";
	var sHandlerName = "";
	sPluginSrc = sPluginSrc.replace(/\s*\*\s*\@pluginDesc\s*(.*)/, "");
 	sPluginDesc = RegExp.$1;

	sPluginSrc = sPluginSrc.replace(/\s*name\s*:\s*["']([^"']+)["']/, "");
	sPluginName = RegExp.$1;
	if(sPluginName == ""){
		sPluginSrc = sPluginSrc.replace(/([^=\r\n]+)\s*=\s*(\$Class.+)[\r\n]*/, "");
		sPluginName = RegExp.$1;
	}

	var oTmpInitiates = {};
	function funcParseInitiator(){
		var sMsgName = arguments[2];
		oTmpInitiates[sMsgName] = "";
		setMsg(sMsgName, "", {});
		return "";
	}

	sPluginSrc.replace(/\.exec\((["'])([^"']+)/g, funcParseInitiator);
	// Save in an object and then convert it to an array to easily avoid duplicate entries
	var oInitiates = [];
	for(var x in oTmpInitiates){
		oInitiates[oInitiates.length] = x;
	}

	var oMsgHandlers = {};
	function funcParseHandler(sHandlerType){
		oMsgHandlers[sHandlerType] = [];

		var sHandlerName = "";
		var sHandlerDesc = "";

		var sRxDesc = "\\/\\*\\(((?:(?!\\)\\*\\/)(?:.|\\r|\\n))+)\\)\\*\\/";
		var sRxHandler = "^\\s*\\$"+sHandlerType+"_([^ :]+)";
		var rxHandler = new RegExp("(?:"+sRxDesc+"[\\s\\r\\n]*)?"+sRxHandler, "gm");

		function funcParseEachHandler(){
			sMsgName = chomp(arguments[2]);
			sHandlerDesc = chomp(arguments[1]);

			var aHandler = oMsgHandlers[sHandlerType];
			aHandler[aHandler.length] = {"Message_NAME": sMsgName,"HANDLER_DESC": sHandlerDesc};
			setMsg(sMsgName, "", {});
		}
		
		sPluginSrc = sPluginSrc.replace(rxHandler, funcParseEachHandler);
	}

	funcParseHandler("BEFORE");
	funcParseHandler("ON");
	funcParseHandler("AFTER");

	aPLUGIN[aPLUGIN.length] = {"PLUGIN_NAME":sPluginName, "PLUGIN_DESC":sPluginDesc, "INITIATES": oInitiates, "Message_HANDLERS": oMsgHandlers};

	return "";
}

function MsgParams2String(aParams){
	var str = "";
	for(var i=0; i<aParams.length; i++){
		str += "<div class='param_block'>";
		str += "<span class='param_name'>"+aParams[i]["PARAM_NAME"]+"</span>";

		if(aParams[i]["PARAM_TYPE"]){
			str += "(";
			str += "<span class='param_type'>"+aParams[i]["PARAM_TYPE"]+"</span>";
			str += ")";
		}

		if(aParams[i]["PARAM_DESC"]){
			str += " : ";
			str += "<span class='param_desc'>"+aParams[i]["PARAM_DESC"]+"</span>";
		}
		str += "</div>";
	}
	return str;
}

function getMsgInitiatorInfo(sMsg){
	var result = [];
	for(var i=0; i<aPLUGIN.length; i++){
		var aAllInitiators = aPLUGIN[i]["INITIATES"];

		for(var ii=0; ii<aAllInitiators.length; ii++){
			if(aAllInitiators[ii] == sMsg) 
				result[result.length] = {"PLUGIN_NAME":aPLUGIN[i]["PLUGIN_NAME"]};
		}
	}

	return result;
}

function InitiatorInfo2String(aAllInitiatorInfo){
	var str = "";
	for(var i=0; i<aAllInitiatorInfo.length; i++){
		str += "<div class='initiator_block'>";
		str += "<span class='initiating_plugin_name'>"+aAllInitiatorInfo[i]["PLUGIN_NAME"]+"</span>";
		str += "</div>";
	}
	return str;
}

function getMsgHandlerInfo(sHandlerType, sMsg){
	var result = [];
	for(var i=0; i<aPLUGIN.length; i++){
		var oAllHandlers = aPLUGIN[i]["Message_HANDLERS"];
		if(oAllHandlers[sHandlerType]){
			var aOneTypeHandlers = oAllHandlers[sHandlerType];
			for(var ii=0; ii<aOneTypeHandlers.length; ii++){
				if(aOneTypeHandlers[ii]["Message_NAME"] == sMsg) 
					result[result.length] = {"PLUGIN_NAME":aPLUGIN[i]["PLUGIN_NAME"], "HANDLER_DESC":aOneTypeHandlers[ii]["HANDLER_DESC"]};
			}
		}
	}

	return result;
}

function HandlerInfo2String(aAllHandlerInfo){
	var str = "";
	for(var i=0; i<aAllHandlerInfo.length; i++){
		var oHandlerInfo = aAllHandlerInfo[i];

		str += "<div class='handler_block'>";
		str += "<span class='handler_plugin_name'>"+oHandlerInfo["PLUGIN_NAME"]+"</span>";
		if(oHandlerInfo["HANDLER_DESC"]){
			str += " : ";
			str += "<span class='handler_desc'>"+oHandlerInfo["HANDLER_DESC"]+"</span>";
		}
		str += "</div>";
	}
	return str;
}

function makeMsgTblFilling(){
	for(var i=0; i<aMessage.length; i++){
		var oMsg = aMessage[i];
		aMsgFilling[aMsgFilling.length] = oMsg["Message_NAME"];
		aMsgFilling[aMsgFilling.length] = MsgParams2String(oMsg["Message_PARAMS"]);
		aMsgFilling[aMsgFilling.length] = oMsg["Message_DESC"];

		var aInitiatorInfo = getMsgInitiatorInfo(oMsg["Message_NAME"]);
		aMsgFilling[aMsgFilling.length] = InitiatorInfo2String(aInitiatorInfo);

		var aOnHandlerInfo = getMsgHandlerInfo("ON", oMsg["Message_NAME"]);
		var aBeforeHandlerInfo = getMsgHandlerInfo("BEFORE", oMsg["Message_NAME"]);
		var aAfterHandlerInfo = getMsgHandlerInfo("AFTER", oMsg["Message_NAME"]);
		aMsgFilling[aMsgFilling.length] = HandlerInfo2String(aOnHandlerInfo);
		aMsgFilling[aMsgFilling.length] = HandlerInfo2String(aBeforeHandlerInfo);
		aMsgFilling[aMsgFilling.length] = HandlerInfo2String(aAfterHandlerInfo);
	}
}

function InitiatorInfo2String4PluginTbl(oPlugin){
	aInitiates = oPlugin["INITIATES"];
	var str = "";
	for(var i=0; i<aInitiates.length; i++){
		str += "<div class='initiator_block'>";
		str += "<span class='initiating_plugin_name'>"+aInitiates[i]+"</span>";
		str += "</div>";
	}
	return str;
}

function HandlerInfo2String4PluginTbl(oPlugin, sHandlerType){
	var str = "";
	var aAllHandlerInfo = oPlugin["Message_HANDLERS"][sHandlerType];
	for(var i=0; i<aAllHandlerInfo.length; i++){
		oHandlerInfo = aAllHandlerInfo[i];
		str += "<div class='handler_block'>";
		str += "<span class='handler_plugin_name'>"+oHandlerInfo["Message_NAME"]+"</span>";
		if(oHandlerInfo["HANDLER_DESC"]){
			str += " : ";
			str += "<span class='handler_desc'>"+oHandlerInfo["HANDLER_DESC"]+"</span>";
		}
		str += "</div>";
	}
	return str;
}

function makePluginTblFilling(){
	for(var i=0; i<aPLUGIN.length; i++){
		var oPlugin = aPLUGIN[i];
		aPluginTblFilling[aPluginTblFilling.length] = oPlugin["PLUGIN_NAME"];
		aPluginTblFilling[aPluginTblFilling.length] = oPlugin["PLUGIN_DESC"];
		aPluginTblFilling[aPluginTblFilling.length] = InitiatorInfo2String4PluginTbl(oPlugin);
		aPluginTblFilling[aPluginTblFilling.length] = HandlerInfo2String4PluginTbl(oPlugin, "ON");
		aPluginTblFilling[aPluginTblFilling.length] = HandlerInfo2String4PluginTbl(oPlugin, "BEFORE");
		aPluginTblFilling[aPluginTblFilling.length] = HandlerInfo2String4PluginTbl(oPlugin, "AFTER");
	}
}

function cmdTblSelected(){
	var oMsgTbl = document.getElementById("idMsgTbl");
	var oPluginTbl = document.getElementById("idPluginTbl");

	var oMsgSpan = document.getElementById("idMsgSpan");
	var oPluginSpan = document.getElementById("idPluginSpan");

	oMsgTbl.style.display = "";
	oPluginTbl.style.display = "none";

	oMsgSpan.className = "selected_view_mode_option";
	oPluginSpan.className = "";
}

function pluginTblSelected(){
	document.getElementById("idPluginSpan");
	var oMsgTbl = document.getElementById("idMsgTbl");
	var oPluginTbl = document.getElementById("idPluginTbl");

	var oMsgSpan = document.getElementById("idMsgSpan");
	var oPluginSpan = document.getElementById("idPluginSpan");

	oMsgTbl.style.display = "none";
	oPluginTbl.style.display = "";

	oMsgSpan.className = "";
	oPluginSpan.className = "selected_view_mode_option";
}

	var aMessage = [];
	var aPLUGIN = [];

	var oMsgTbl = new HTMLElmWrapper.wrapperTable("idMsgTbl");
	var nMsgTblColumns = 7;
	var aMsgFilling = [];

	var oPluginTbl = new HTMLElmWrapper.wrapperTable("idPluginTbl");
	var nPluginTblColumns = 6;
	var aPluginTblFilling = [];

function displayHuskyManual(){
	var tmp = document.getElementById("file_list").value;
	tmp = tmp.replace(/\r/g, "\n").replace(/\n+/g, "\n");
	window.aFileList = tmp.split("\n");

	var xhr = new XMLHttpRequest();
	for(var i=0; i<aFileList.length; i++){
		xhr.open("GET", aFileList[i], false);
		xhr.send("");
		content = xhr.responseText;
		content = content.replace(/\/\*\[(((?!-*\]\*\/)(.|\n|\r))+)/g, funcParseOneMsgCmt);
		funcParseOnePluginSrc(content);
	}
	aMessage.sort(function(a, b){
		if(a["Message_NAME"]>b["Message_NAME"]) return 1;
		if(a["Message_NAME"]<b["Message_NAME"]) return -1;
		return 0;
	});

	aPLUGIN.sort(function(a, b){
		if(a["PLUGIN_NAME"]>b["PLUGIN_NAME"]) return 1;
		if(a["PLUGIN_NAME"]<b["PLUGIN_NAME"]) return -1;
		return 0;
	});

	makeMsgTblFilling();
	oMsgTbl.createCells(nMsgTblColumns, aMessage.length);
	oMsgTbl.fill(aMsgFilling);

	makePluginTblFilling();
	oPluginTbl.createCells(nPluginTblColumns, aPLUGIN.length);
	oPluginTbl.fill(aPluginTblFilling);

	document.getElementById("idMsgSpan").onclick=cmdTblSelected;
	document.getElementById("idPluginSpan").onclick=pluginTblSelected;

	cmdTblSelected();
	
	document.getElementById("file_list_div").style.display = "none";
	document.getElementById("doc_table_div").style.display = "block";
}
</script>
</html>